using System;
using System.Data;
using System.Runtime.Serialization;

namespace FreeFlow.Administration
{
  /// <summary>
  /// The type of an action
  /// </summary>
  public enum ActionType
  {
    /// <summary>Unknown action type</summary>
    None=0,
    /// <summary>User action</summary>
    User=1,
    /// <summary>Timed action</summary>
    Timed=2,
    /// <summary>Flagged action</summary>
    Flagged=3,
    /// <summary>Conditional action</summary>
    Conditional=4,
    /// <summary>Rendezvous action</summary>
    Rendezvous=5
  }

  /// <summary>
  /// What will happen to the To Do list after a folder returns to the stage after a loopback action
  /// </summary>
  public enum LoopbackOption
  {
    /// <summary>Not applicable, the action is not a loopback action.</summary>
    None,
    /// <summary>The folder will be removed from the user's To Do list</summary>
    [EnumDescription("Remove from To Do list")]
    RemoveFromToDoList,
    /// <summary>The To Do list will be rebuilt</summary>
    [EnumDescription("Rebuild To Do list")]
    RebuildToDoList,
    /// <summary>The To Do list will remain unchanged</summary>
    [EnumDescription("Leave it")]
    LeaveIt
  }

	/// <summary>
	/// An action in a map.
	/// </summary>
	public class Action : DatabaseAware, IUpdatable
	{
    private Map map;
		internal Action(Server server, Map map, IDataReader reader) :  base(server)
		{
      this.map = map;
      name = reader["eActionName"].ToString();
      priority = Convert.ToInt16(reader["eActionID"]);
      fromStage = reader["eStageName"].ToString().Trim();
      toStage = reader["eToStage"].ToString();
      
      form = reader["eUserPage"].ToString();
      if (form == "?")
      {
        form = string.Empty;
        userActionType = UserActionType.Confirm;
      }
      else if (form == "!")
      {
        form = string.Empty;
        userActionType = UserActionType.NonConfirm;
      }
      else
        userActionType = UserActionType.Form;

      mapName = reader["eMapName"].ToString();
      actionType = (ActionType)Convert.ToInt16(reader["eActionType"]);
      if (reader["eDoCopy"]  != System.DBNull.Value)
        cloneFolder = Convert.ToBoolean(reader["eDoCopy"]);
      alertMessage = reader["eAlertMessage"].ToString();
      chainedAction = reader["eChainedAction"].ToString();
      if (reader["eChain"]  != System.DBNull.Value)
        reopenFolder = Convert.ToBoolean(reader["eChain"]);
      triggeredByFlag = reader["eFlag"].ToString();
      raiseFlag = reader["eRaiseFlag"].ToString();
      availableTo = reader["eUserAccess"].ToString();
      whenStarted = reader["eOnInvoke"].ToString();
      whenCompleted = reader["eOnCommit"].ToString();
      afterTime = reader["eAfterTime"].ToString();
      if (toStage == fromStage)
        loopbackOption = LoopbackOption.RebuildToDoList;
      else if (string.IsNullOrEmpty(toStage))
      {
        if (Convert.ToInt16(reader["eRemoveFromToDoList"]) == 1)
          loopbackOption = LoopbackOption.RemoveFromToDoList;
        else
          loopbackOption = LoopbackOption.LeaveIt;

        // to be consistent, always show to stage
        toStage = fromStage;
      }

      fieldUsage = new FieldUsageCollection(reader);

      if (IsCreation && actionType == ActionType.User)
      {
        // read values from eStart
        group = reader["eGroupName"].ToString();
        description = reader["eDescription"].ToString();
      }
		}

    private string name;
    /// <summary>
    /// Gets the name of the action.
    /// </summary>
    public string Name
    {
      get
      {
        return name;
      }
    }

    private int priority;
    /// <summary>
    /// Gets the priority of the action.
    /// </summary>
    public int Priority
    {
      get
      {
        return priority;
      }
    }

    private string fromStage;
    /// <summary>
    /// Gets the stage that the action comes from.
    /// </summary>
    public string FromStage
    {
      get
      {
        return fromStage;
      }
    }

    private string toStage;
    /// <summary>
    /// Gets the name of the stage that the action is going to.
    /// </summary>
    public string ToStage
    {
      get
      {
        return toStage;
      }
    }

    /// <summary>
    /// Gets a value indicating whether this action is a loopback action.
    /// </summary>
    /// <value>
    /// 	<c>true</c> if this action is a loopback action; otherwise, <c>false</c>.
    /// </value>
    public bool IsLoopback
    {
      get
      {
        return fromStage == toStage;
      }
    }

    /// <summary>
    /// Gets a value indicating whether this action is a creation action.
    /// </summary>
    /// <value>
    /// 	<c>true</c> if this action is a creation action; otherwise, <c>false</c>.
    /// </value>
    public bool IsCreation
    {
      get
      {
        return string.IsNullOrEmpty(fromStage);
      }
    }

    private string form;
    /// <summary>
    /// Gets the form used in this action, if it is a user action.
    /// </summary>
    public string Form
    {
      get
      {
        return form;
      }
    }

    private string mapName;
    /// <summary>
    /// Gets the name of the map that this action belongs to.
    /// </summary>
    public string MapName
    {
      get
      {
        return mapName;
      }
    }

    private ActionType actionType;
    /// <summary>
    /// Gets the type of the action.
    /// </summary>
    public ActionType ActionType
    {
      get
      {
        return actionType;
      }
    }

    private bool cloneFolder;
    /// <summary>
    /// Gets a value indicating whether this <see cref="Action"/> will clone the folder.
    /// </summary>
    /// <value><c>true</c> if the action will clone the folder; otherwise, <c>false</c>.</value>
    public bool CloneFolder
    {
      get
      {
        return cloneFolder;
      }
    }

    private string alertMessage;
    /// <summary>
    /// Gets the alert message formula for the action.
    /// </summary>
    public string AlertMessage
    {
      get
      {
        return alertMessage;
      }
    }

    private string chainedAction;
    /// <summary>
    /// Gets the chained action formula, for a user action.
    /// </summary>
    public string ChainedAction
    {
      get
      {
        return chainedAction;
      }
    }

    private bool reopenFolder;
    /// <summary>
    /// Gets a value indicating whether this action will reopen the folder, if this is a user action.
    /// </summary>
    /// <value><c>true</c> if this action will reopen the folder; otherwise, <c>false</c>.</value>
    public bool ReopenFolder
    {
      get
      {
        return reopenFolder;
      }
    }

    private string triggeredByFlag;
    /// <summary>
    /// Gets the name of the flag that will trigger this action.
    /// </summary>
    public string TriggeredByFlag
    {
      get
      {
        return triggeredByFlag;
      }
    }

    private string raiseFlag;
    /// <summary>
    /// Gets the name of the flag that this action will raise.
    /// </summary>
    public string RaiseFlag
    {
      get
      {
        return raiseFlag;
      }
    }

    private string availableTo;
    /// <summary>
    /// Gets the formula that will be evaluated to decide which users will have access to this action, if it is a user action.
    /// </summary>
    public string AvailableTo
    {
      get
      {
        return availableTo;
      }
    }

    private string whenStarted;
    /// <summary>
    /// Gets the formula that will be evaluated when the action is started.
    /// </summary>
    public string WhenStarted
    {
      get
      {
        return whenStarted;
      }
    }

    private string whenCompleted;
    /// <summary>
    /// Gets the formula that will be evaluated when the action is completed.
    /// </summary>
    public string WhenCompleted
    {
      get
      {
        return whenCompleted;
      }
    }

    private string afterTime;
    /// <summary>
    /// Gets the formula that will be evaluated to deicde when a timed action will be triggered.
    /// </summary>
    public string AfterTime
    {
      get
      {
        return afterTime;
      }
    }

    private LoopbackOption loopbackOption = LoopbackOption.None;
    /// <summary>
    /// Indicates what will happen to the folder's To Do list after returning from a loopback action.
    /// </summary>
    public LoopbackOption LoopbackOption
    {
      get
      {
        return loopbackOption;
      }
    }

    private FieldUsageCollection fieldUsage;
    /// <summary>
    /// Gets the field usage for the action.
    /// </summary>
    /// <value>The field usage.</value>
    public FieldUsageCollection FieldUsage
    {
      get
      {
        return fieldUsage;
      }
    }

    private UserActionType userActionType;
    /// <summary>
    /// For a user action, gets the type of the user interaction required.
    /// </summary>
    public UserActionType UserActionType
    {
      get
      {
        return userActionType;
      }
    }

    private const string exceptionMessage = "This is not a creation user action";
    private string group;
    /// <summary>
    /// For a creation user action, gets or sets the group for the action.
    /// </summary>
    public string Group
    {
      get
      {
        return group;
      }
      set
      {
        if (IsCreation && actionType == ActionType.User)
        {
          group = value;
        }
        else
        {
          throw new ArgumentException(exceptionMessage);
        }
      }
    }

    private string description;
    /// <summary>
    /// For a creation user action, gets the description for the action.
    /// </summary>
    public string Description
    {
      get
      {
        return description;
      }
    }

    #region IUpdatable Members

    /// <summary>
    /// Applies the changes made to this action (will set the group for a user creation action).
    /// </summary>
    public void ApplyChanges()
    {
      if (IsCreation && actionType == ActionType.User)
      {
        Server.ExecuteNonQuery(string.Format("UPDATE eStart SET eGroupName = '{0}' WHERE eMapName = '{1}' AND eActionName = '{2}'", 
          DatabaseAware.SqlEscape(group), DatabaseAware.SqlEscape(mapName), DatabaseAware.SqlEscape(name)));
      }
      else
      {
        throw new FreeFlowException(exceptionMessage);
      }
    }

    #endregion

    internal int foldersPassThroughCount = -1;
    /// <summary>
    /// Gets the number of folders that have passed through this action.
    /// </summary>
    public int FoldersPassThroughCount
    {
      get
      {
        if (foldersPassThroughCount == -1)
          map.GetStatistics();

        return foldersPassThroughCount;
      }
    }

    internal int eventCount = -1;
    /// <summary>
    /// Gets the number of events that have occurred with this action.
    /// </summary>
    public int EventCount
    {
      get
      {
        if (eventCount == -1)
          map.GetStatistics();

        return eventCount;
      }
    }
  } 
}
